#include "HTTPSessionHandler.h"
#include "Poco/StreamCopier.h"

HTTPSessionHandler::HTTPSessionHandler(const std::string& targetHost, int targetPort)
    : _targetHost(targetHost), _targetPort(targetPort) {}

void HTTPSessionHandler::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) {
    try {
        std::cout << "Proxying HTTP Request: " << request.getMethod() << " " << request.getURI() << " to " << _targetHost << ":" << _targetPort << std::endl;

        Poco::Net::HTTPClientSession session(_targetHost, _targetPort);
        Poco::Net::HTTPRequest backendRequest(request.getMethod(), request.getURI(), request.getVersion());

        // Copy all request headers
        Poco::Net::HTTPServerRequest::ConstIterator it = request.begin();
        Poco::Net::HTTPServerRequest::ConstIterator end = request.end();
        for (; it != end; ++it) {
            // Avoid copying hop-by-hop headers if not handled properly by proxy_pass
            // For simplicity, we copy all. In real world, filter out "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "TE", "Trailers", "Transfer-Encoding", "Upgrade"
            std::cout << "Reward header:" << (it->first) << "\n";
            backendRequest.set(it->first, it->second);
        }

        // Forward request body if any
        if (request.hasContentLength() || request.getChunkedTransferEncoding()) {
            std::cout << "send request...\n";
            Poco::StreamCopier::copyStream(request.stream(), session.sendRequest(backendRequest));
        } else {
            session.sendRequest(backendRequest);
        }

        Poco::Net::HTTPResponse backendResponse;
        std::istream& backendResponseStream = session.receiveResponse(backendResponse);

        // Set response status and copy headers from backend to client
        response.setStatus(backendResponse.getStatus());
        response.setReason(backendResponse.getReason());

        Poco::Net::HTTPResponse::ConstIterator backendIt = backendResponse.begin();
        Poco::Net::HTTPResponse::ConstIterator backendEnd = backendResponse.end();
        for (; backendIt != backendEnd; ++backendIt) {
            response.set(backendIt->first, backendIt->second);
        }

        // Copy response body
        if (backendResponse.hasContentLength() || backendResponse.getChunkedTransferEncoding()) {
            Poco::StreamCopier::copyStream(backendResponseStream, response.send());
        } else {
            // For responses without content-length or chunked, just close the response stream
            response.send();
        }

    } catch (Poco::Exception& exc) {
        std::cerr << "HTTP Proxy Error: " << exc.displayText() << std::endl;
        std::cerr << "HTTP Proxy Error: " << exc.message() << "" << std::endl; // Try message() too

        response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
        std::string str_content = "HTTP Proxy Error: " + exc.displayText();
        response.send().write(str_content.c_str(), str_content.size());
    }
}